home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / ada / adaed-1.11 / adaed-1 / Adaed-1.11.0a / predef4.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-02-07  |  22.8 KB  |  926 lines

  1. /*
  2.  * Copyright (C) 1985-1992  New York University
  3.  * 
  4.  * This file is part of the Ada/Ed-C system.  See the Ada/Ed README file for
  5.  * warranty (none) and distribution info and also the GNU General Public
  6.  * License for more details.
  7.  
  8.  */
  9. /*    +---------------------------------------------------+
  10.       |                                                   |
  11.       |          I N T E R P     P R E D E F S            |
  12.       |         Part 4: Input/Output Procedures           |
  13.       |                  (C Version)                      |
  14.       |                                                   |
  15.       |   Adapted From Low Level SETL version written by  |
  16.       |                                                   |
  17.       |                  Monte Zweben                     |
  18.       |               Philippe Kruchten                   |
  19.       |               Jean-Pierre Rosen                   |
  20.       |                                                   |
  21.       |    Original High Level SETL version written by    |
  22.       |                                                   |
  23.       |                   Clint Goss                      |
  24.       |               Tracey M. Siesser                   |
  25.       |               Bernard D. Banner                   |
  26.       |               Stephen C. Bryant                   |
  27.       |                  Gerry Fisher                     |
  28.       |                                                   |
  29.       |              C version written by                 |
  30.       |                                                   |
  31.       |               Robert B. K. Dewar                  |
  32.       |                                                   |
  33.       +---------------------------------------------------+
  34. */
  35.  
  36. /*  This module contains routines for the implementation of some of
  37.  *  the predefined Ada packages and routines, namely SEQUENTIAL_IO,
  38.  *  DIRECT_IO, TEXT_IO, and CALENDAR. Part 4 contains the initialization
  39.  *  and termination routines for predef, and the basic I/O routines
  40. */
  41.  
  42. #include <stdlib.h>
  43. #include <string.h>
  44. #ifdef IBM_PC
  45. #include <io.h>
  46. #endif
  47. #include "ipredef.h"
  48. #include "miscprots.h"
  49. #include "predefprots.h"
  50.  
  51. static void check_ifile_closed(int *);
  52. static void check_xfile_closed(char *);
  53. static void open_file();
  54. #ifdef IBM_PC
  55. static int stdin_is_console();
  56. #undef putc
  57. #define putc(A, B) fputc((A),(B));fflush(B)
  58. #endif
  59. static void clear_eof();
  60. static int fgetceof(FILE *);
  61. #ifdef DEBUG_PREDEF
  62. static void gchar(char *, int);
  63. static void pchar(char *, int);
  64. #endif
  65.  
  66. /* AFCB for STANDARD_IN_FILE */
  67.  
  68. static struct afcb  in_afcb = {
  69.  
  70.     0,                          /* file descriptor for standard input */
  71.     "",                         /* file name(null) */
  72.     "",                         /* form string(null) */
  73.     TIO_IN_FILE,                /* mode, TEXT_IO input */
  74. #ifdef IO_EOF
  75.     0,                          /* eof flag */
  76. #endif
  77.     0, 0, 0,                    /* unused DIRECT_IO fields */
  78.     1,                          /* page number */
  79.     1,                          /* line number */
  80.     1,                          /* column number */
  81.     0,                          /* unbounded line length */
  82.     0,                          /* unbounded page length */
  83.     0, "  "                    /* look ahead */
  84. };
  85.  
  86. #ifdef IBM_PC
  87. /* keep track of last character read from stdin so can detect whether we
  88.  * need to flush what is left there before exiting
  89.  */
  90. static int last_char_input = EOF;
  91. #endif
  92.  
  93. /* AFCB for STANDARD_OUT_FILE */
  94.  
  95. static struct afcb  out_afcb = {
  96.  
  97.     0,                          /* file descriptor for standard input */
  98.     "",                         /* file name(null) */
  99.     "",                         /* form string(null) */
  100.     TIO_OUT_FILE,               /* mode, TEXT_IO output */
  101. #ifdef IO_EOF
  102.     0,                /* eof flag */
  103. #endif
  104.     0, 0, 0,                    /* unused DIRECT_IO fields */
  105.     1,                          /* page number */
  106.     1,                          /* line number */
  107.     1,                          /* column number */
  108.     0,                          /* unbounded line length */
  109.     0,                          /* unbounded page length */
  110.     0, "  "                    /* look ahead */
  111. };
  112.  
  113. /* Procedure to initialize input/output data structures */
  114.  
  115. void initialize_predef()                     /*;initialize_predef*/
  116. {
  117.     /* Clear temporary file list, and clear AFCB vector */
  118.  
  119.     tfiles = 0;
  120.     for (filenum = 1; filenum <= MAXFILES; filenum++)
  121.         afcbs[filenum - 1] = 0;
  122.  
  123.     /* Setup references for current and standard files */
  124.  
  125.     current_in_file = 1;
  126.     current_in_file_saved = 1;
  127.     standard_in_file = 1;
  128.     afcbs[0] = &in_afcb;
  129.     filenum = 1;
  130.     IOFDESC = stdin;
  131.     CHARS = 0;
  132.  
  133.     current_out_file = 2;
  134.     current_out_file_saved = 2;
  135.     standard_out_file = 2;
  136.     afcbs[1] = &out_afcb;
  137.     filenum = 2;
  138.     IOFDESC = stdout;
  139.  
  140.     /* Set standard exception signalled on bad data (changed temporarily
  141.      * to CONSTRAINT_ERROR when TEXT_IO routines are called directly from
  142.      * the main interpretor for the IMAGE attribute.
  143.      */
  144.  
  145.     data_exception = DATA_ERROR;
  146. }
  147.  
  148.  
  149. /* CHECK_OPENED_OK */
  150.  
  151. /* Checks that an fopen succeeded, raise USE_ERROR if not */
  152.  
  153. void check_opened_ok()                                   /*;check_opened_ok*/
  154. {
  155.     if (IOFDESC == NULL)
  156.         predef_raise(USE_ERROR, "Error opening or resetting file");
  157. }
  158.  
  159. /* CHECK_IFILE_CLOSED */
  160.  
  161. /* Checks that the file object stored at file_ptr is closed */
  162.  
  163. static void check_ifile_closed(int *file_ptr)           /*;check_ifile_closed*/
  164. {
  165.     int     file_val;
  166.  
  167.     file_val = *file_ptr;
  168.     if (file_val != 0)
  169.         predef_raise(STATUS_ERROR, "File not closed");
  170. }
  171.  
  172. /* CHECK_XFILE_CLOSED */
  173.  
  174. /* Checks that no external file with a matching name is currently open */
  175.  
  176. static void check_xfile_closed(char *fname)             /*;check_xfile_closed*/
  177. {
  178.     int     i;
  179.     for (i = 1; i <= MAXFILES; i++) {
  180.         if (afcbs[i - 1] == NULL) continue;
  181.         if (strcmp(fname, afcbs[i - 1] -> io_fname) == 0 &&
  182.           afcbs[i - 1] -> io_fdesc != NULL) {
  183.             predef_raise(USE_ERROR, "File already open");
  184.         }
  185.     }
  186. }
  187.  
  188. /* CHECK_FILE_OPEN */
  189.  
  190. /* Check if the current file is open or not. If the file is not open,
  191.   * then STATUS_ERROR is raised. Otherwise control returns normally.
  192. */
  193.  
  194. void check_file_open()                                       /*;check_file_open*/
  195. {
  196.     if (filenum == 0)
  197.         predef_raise(STATUS_ERROR, "File not open");
  198. }
  199.  
  200. /* If the current file is not open, then STATUS_ERROR is raised. If
  201.  * the file is open, then the mode is checked against the argument which
  202.  * is the desired mode for the operation. If it does not match, then
  203.  * MODE_ERROR is raised, otherwise control returns normally.
  204.  */
  205.  
  206. void check_status(int c_mode)                                /*;check_status*/
  207. {
  208.     check_file_open();
  209.     if (IOMODE != c_mode)
  210.         predef_raise(MODE_ERROR, "Incorrect file status");
  211. }
  212.  
  213. /*  Routine called by the OPEN and CREATE portions of the PREDEF procedure
  214.  *  to perform common data structure operations for TEXT_IO operations.
  215.  *  The operation in opn is 'C' for a create and 'O' for an open.
  216.  */
  217.  
  218. void open_textio(char opn)                       /*;open_textio*/
  219. {
  220.     open_file();
  221.  
  222. #ifdef SYSTEM_V
  223.     if (strlen(IOFNAME) > 14) predef_raise(NAME_ERROR,"Invalid file name");
  224. #endif
  225.  
  226.     if (opn == 'C') {
  227.         IOFDESC = fopen_txt(IOFNAME, "w");
  228.         if (IOFDESC == NULL) predef_raise(NAME_ERROR,"Invalid file name");
  229.         if (IOMODE == SIO_IN_FILE) {
  230.             fclose(IOFDESC);
  231.             IOFDESC = fopen_txt(IOFNAME, "r");
  232.             check_opened_ok();
  233.         }
  234.     }
  235.     else {                      /* opn == 'O' */
  236.         /*
  237.         * According to AI-00048: 
  238.         * Opening a file with IN_FILE mode which is the default output file 
  239.         * will raise MODE_ERROR. 
  240.         * Opening a file with OUT_FILE mode which is the default input file 
  241.         * will raise MODE_ERROR.
  242.         * The values to be checked is in current_in_file_saved and
  243.         * current_out_file_saved which are copies of the file numbers
  244.         * associated with the default files. These copies must be used
  245.         * because when the default files are closed their filenums saved
  246.         * in current_XXX_file are set to zero and therefore lost for this
  247.         * check.
  248.         */
  249.         if (filenum == current_in_file_saved && IOMODE == TIO_OUT_FILE)
  250.             predef_raise(MODE_ERROR,"File is default in file");
  251.         if (filenum == current_out_file_saved && IOMODE == TIO_IN_FILE)
  252.             predef_raise(MODE_ERROR,"File is default out file");
  253.         IOFDESC = fopen_txt(IOFNAME, "r");
  254.         if (IOFDESC == NULL) predef_raise(NAME_ERROR,"File not found");
  255.         if (IOMODE == TIO_IN_FILE)
  256.             CHARS = 0;
  257.         else {
  258.             fclose(IOFDESC);
  259.             IOFDESC = fopen_txt(IOFNAME, "w");
  260.             check_opened_ok();
  261.         }
  262.     }
  263.  
  264.     PAGE = 1;
  265.     LINE = 1;
  266.     COL = 1;
  267.     LINE_LENGTH = 0;
  268.     PAGE_LENGTH = 0;
  269.  
  270.     *get_argument_ptr(0) = filenum;
  271. }
  272.  
  273. /* LOAD_LOOK_AHEAD */
  274.  
  275. /* This procedure loads the lookahead for a TEXT_IO input file, leaving
  276.  * CHARS set to 3 (unless the file is less than 3 bytes long), and CHAR1
  277.  * CHAR2 and CHAR3 containing the initial characters of the file. A special
  278.  * exception occurs with the standard input file, where we never read ahead
  279.  * more than one character, because of problems with interactive I/O.
  280. */
  281.  
  282. void load_look_ahead()                                       /*;load_look_ahead*/
  283. {
  284.     int c;
  285.  
  286.     /* Load first character of look ahead */
  287.  
  288.     if (CHARS == 0) {
  289.         CHAR2 = CHAR3 = 0;
  290. #ifdef IO_EOF
  291.         c = fgetceof(IOFDESC);
  292. #else
  293.         c = fgetc(IOFDESC);
  294. #endif
  295.  
  296. #ifdef IBM_PC
  297.         if (IOFDESC == stdin)
  298.             last_char_input = c;
  299. #endif
  300.         gchar("load_look 1", c);
  301.         if (c == EOF) {
  302.             CHAR1 = 0;
  303.             return;
  304.         }
  305.         else {
  306.             CHAR1 = c;
  307.             CHARS = 1;
  308.         }
  309.     }
  310.  
  311.     /* Leave lookahead with one character loaded if standard input */
  312.  
  313.     if (IOFDESC != stdin) {
  314.  
  315.         /* Load second character of look ahead */
  316.  
  317.         if (CHARS == 1) {
  318.             CHAR3 = 0;
  319. #ifdef IO_EOF
  320.             c = fgetceof(IOFDESC);
  321. #else
  322.             c = fgetc(IOFDESC);
  323. #endif
  324.             gchar("load_look 2",c);
  325.             if (c == EOF) {
  326.                 CHAR2 = 0;
  327.                 return;
  328.             }
  329.             else {
  330.                 CHAR2 = c;
  331.                 CHARS = 2;
  332.             }
  333.         }
  334.  
  335.         /* Load third character of look ahead */
  336.  
  337.         if (CHARS == 2) {
  338. #ifdef IO_EOF
  339.             c = fgetceof(IOFDESC);
  340. #else
  341.             c = fgetc(IOFDESC);
  342. #endif
  343.             gchar("load_look 3",c);
  344.             if (c == EOF) {
  345.                 CHAR3 = 0;
  346.                 return;
  347.             }
  348.             else {
  349.                 CHAR3 = c;
  350.                 CHARS = 3;
  351.             }
  352.         }
  353.     }
  354. }
  355.  
  356. /* CLOSE_TEXTIO */
  357.  
  358. /*  This routine is called by the CLOSE portion of the PREDEF procedure to
  359.  *  perform common data structure operations for text_io. Perform various
  360.  *  actions based on whether this is an input or output file.
  361.  */
  362.  
  363. void close_textio()                                          /*;close_text_io*/
  364. {
  365.     if (IOMODE == TIO_OUT_FILE) {
  366.  
  367.         /* Simulate effect of NEW_PAGE unless current page is terminated */
  368.  
  369.         if (!PAGE_TERMINATED) {
  370.             if (COL > 1 ||(COL == 1 && LINE == 1))
  371.                 put_line();
  372.             put_page();
  373.         }
  374.     }
  375.  
  376.     /* Sever the association between the given file and its associated
  377.      * external file.   The given file is left closed.  Do not perform
  378.      * system closes on the standard input and output files.
  379.      */
  380.  
  381.     if (filenum != standard_in_file && filenum != standard_out_file)
  382.         close_file();
  383.  
  384.     /* If the file being closed is one of the default files, set the default
  385.      * file indicator to zero to indicate that the file is closed.
  386.      */
  387.  
  388.     if (filenum == current_in_file)
  389.         current_in_file = 0;
  390.     else if (filenum == current_out_file)
  391.         current_out_file = 0;
  392. }
  393.  
  394. /*  TEXT_IO Line Management Procedures */
  395.  
  396. /* GET_CHAR */
  397.  
  398. /*  Procedure to get the next character from the current text input file.
  399.  *  If no character is available, then END_ERROR is raised.
  400.  */
  401.  
  402. char get_char()                                                     /*;get_char*/
  403. {
  404.     char    c;                          /* character read */
  405.  
  406.     /* Load look ahead and check for no more characters */
  407.  
  408.     load_look_ahead();
  409.     if (CHARS == 0)
  410.         predef_raise(END_ERROR, "End of file on TEXT_IO input");
  411.     c = CHAR1;
  412.  
  413.     /* Update lookahead */
  414.  
  415.     CHAR1 = CHAR2;
  416.     CHAR2 = CHAR3;
  417.     CHAR3 = 0;
  418.     CHARS--;
  419.  
  420.     /* Update PAGE and LINE counters if page mark or line feed read */
  421.  
  422.     if (c == PAGE_MARK) {
  423.         PAGE += 1;
  424.         LINE = 1;
  425.         COL = 1;
  426.     }
  427.     else if (c == LINE_FEED) {
  428.         LINE += 1;
  429.         COL = 1;
  430.     }
  431.     else
  432.         COL += 1;
  433.     if (c > 127)
  434.         predef_raise(DATA_ERROR, "Character > 127 for TEXT_IO input");
  435.     gchar("get_char",c);
  436.     return c;
  437. }
  438.  
  439. /* SKIP_LINE */
  440.  
  441. /* Procedure to perform SKIP_LINE operation for a spacing of 1 line. Skips
  442.  * characters up to and including next line terminator. Also skips any
  443.  * page marks following this line terminator (there should normally be at
  444.  * most one in standard format files, but we just skip past several if
  445.  * we find them present).
  446. */
  447.  
  448. void skip_line()                                                 /*;skip_line*/
  449. {
  450.     for (;;) {
  451.         load_look_ahead();
  452.         if (get_char() == LINE_FEED)
  453.             break;
  454.     }
  455.  
  456.     /* ignore page marks for standard input. */
  457.  
  458.     if (IOFDESC == stdin) return;
  459.  
  460.     for (;;) {
  461.         load_look_ahead();
  462.         if (CHAR1 != PAGE_MARK) break;
  463.         get_char();
  464.     }
  465. }
  466.  
  467. /* PUT_BLANKS */
  468.  
  469. /* Procedure to write n blanks to current text file. There is no check for
  470.  * line overflow, it is assumed that the caller has checked line overflow.
  471.  */
  472.  
  473. void put_blanks(int n)                                           /*;put_blanks*/
  474. {
  475.     while (n--) {
  476.         pchar("put_blanks",' ');
  477.         putc(' ', IOFDESC);
  478.     }
  479. }
  480.  
  481. /* PUT_CHAR */
  482.  
  483. /* Procedure to write 1 character to current text file. Functions exactly
  484.  * as if writing a one character string(see PUT_STRING function)
  485.  */
  486.  
  487. void put_char(char c)                                             /*;put_char*/
  488. {
  489.     if (BOUNDED_LINE_LENGTH && COL > LINE_LENGTH )
  490.         put_line();
  491.     pchar("put_char",c);
  492.     putc(c, IOFDESC);
  493.     COL++;
  494. }
  495.  
  496. /* PUT_LINE */
  497.  
  498. /* This procedure outputs a line feed to the current text file */
  499.  
  500. void put_line()                                                      /*;put_line*/
  501. {
  502.     pchar("put_line",LINE_FEED);
  503.     putc(LINE_FEED, IOFDESC);
  504.     COL = 1;
  505.     if (BOUNDED_PAGE_LENGTH && LINE >= PAGE_LENGTH)
  506.         put_page();
  507.     else LINE += 1;
  508. }
  509.  
  510. /* PUT_PAGE */
  511.  
  512. /* Procedure to write page mark to current text file */
  513.  
  514. void put_page()                                                  /*;put_page*/
  515. {
  516.     pchar("put_page",PAGE_MARK);
  517.     putc(PAGE_MARK, IOFDESC);
  518.     PAGE += 1;
  519.     LINE = 1;
  520.     COL = 1;
  521. }
  522.  
  523. /* Put a string into the output file, performing line breaks as needed */
  524.  
  525. void put_string(char *s)                                       /*;put_string*/
  526. {
  527.     int     left_in_string;             /* chars left in string */
  528.     int     left_in_line;               /* chars left in current line */
  529.  
  530.     left_in_string = strlen(s);
  531.  
  532.     if (UNBOUNDED_LINE_LENGTH) {
  533.         COL += left_in_string;
  534.         while (left_in_string--) {
  535.             pchar("put_string 1",*s);
  536.             putc(*s++,IOFDESC);
  537.         }
  538.     }
  539.  
  540.     else {
  541.         while(left_in_string != 0) {
  542.             left_in_line = LINE_LENGTH - COL + 1;
  543.             if (left_in_line <= 0) {
  544.                 put_line();
  545.                 left_in_line = LINE_LENGTH;
  546.             }
  547.  
  548.             if (left_in_string <= left_in_line) {
  549.                 COL += left_in_string;
  550.                 while (left_in_string) {
  551.                     pchar("put_string 2",*s);
  552.                     putc(*s++,IOFDESC);
  553.                     /* left_in_string should never become negative */
  554.                     left_in_string--;
  555.                 }
  556.             }
  557.             else {
  558.                 left_in_string -= left_in_line;
  559.                 while (left_in_line--) {
  560.                     pchar("put_string 3",*s);
  561.                     putc(*s++,IOFDESC);
  562.                 }
  563.                 put_line();
  564.             }
  565.         }
  566.     }
  567. }
  568.  
  569.  
  570. /* PUT_BUFFER */
  571.  
  572. /*  This routine writes an item(passed in as a string) with appropriate
  573.  *  blank padding. The second parameter is the desired width, and the third
  574.  *  parameter is 'L' for leading blank padding and 'T' for trailing padding.
  575.  */
  576.  
  577. void put_buffer(char *buffer, int width, char padtype)          /*;put_buffer*/
  578. {
  579.     int     slength, tlength;
  580.     int n;
  581.  
  582.     slength = strlen(buffer);
  583.     if (slength < width)
  584.         tlength = width;
  585.     else {
  586.         tlength = slength;
  587.         padtype = ' ';
  588.     }
  589.  
  590.     /* Ensure the buffer size does not exceed the line length */
  591.  
  592.     if (BOUNDED_LINE_LENGTH) {
  593.         if (tlength > LINE_LENGTH)
  594.             predef_raise(LAYOUT_ERROR, "Line too big");
  595.  
  596.         /* New line if does not fit on current line */
  597.  
  598.         if (COL + tlength - 1 > LINE_LENGTH)
  599.             put_line();
  600.     }
  601.  
  602.     /* Output data with required padding */
  603.  
  604.     if (padtype == 'L')
  605.         put_blanks(width - slength);
  606.     n = slength;
  607.     while (n--) {
  608.         pchar("put_buffer",*buffer);
  609.         putc(*buffer++,IOFDESC);
  610.     }
  611.     COL += tlength;
  612.     if (padtype == 'T')
  613.         put_blanks(width - slength);
  614. }
  615.  
  616. /* OPEN_SEQ_IO */
  617.  
  618. /*  Create or open a SEQUENTIAL_IO file. If the file is to be created,
  619.  *  an AFCB is created and initialized to empty. If the file is to be opened,
  620.  *  the existing file is accessed, and the AFCB initialized for that file.
  621.  *  The argument opn is 'C' to create a file and 'O' to open a file.
  622.  */
  623.  
  624. void open_seq_io(int opn)                                        /*;open_seq*/
  625. {
  626.     DISCARD_GENERIC_PARAMETER;
  627.  
  628.     open_file();
  629.  
  630. #ifdef SYSTEM_V
  631.     if (strlen(IOFNAME) > 14) predef_raise(NAME_ERROR,"Invalid file name");
  632. #endif
  633.  
  634.     if (opn == 'C') {
  635.         IOFDESC = fopen_bin(IOFNAME, "w");
  636.         if (IOFDESC == NULL) predef_raise(NAME_ERROR,"Invalid file name");
  637.         if (IOMODE == SIO_IN_FILE) {
  638.             fclose(IOFDESC);
  639.             IOFDESC = fopen_bin(IOFNAME, "r");
  640.             check_opened_ok();
  641.         }
  642.     }
  643.     else {                      /* opn == 'O' */
  644.         IOFDESC = fopen_bin(IOFNAME, "r");
  645.         if (IOFDESC == NULL) predef_raise(NAME_ERROR,"File not found");
  646.         if (IOMODE == SIO_IN_FILE)
  647.             ;
  648.         else {
  649.             fclose(IOFDESC);
  650.             IOFDESC = fopen_bin(IOFNAME, "w");
  651.             check_opened_ok();
  652.         }
  653.     }
  654.     *get_argument_ptr(0) = filenum;
  655. }
  656.  
  657. /* OPEN_DIR_IO */
  658.  
  659. /*  Open or create a DIRECT_IO file. If the file is to be created, an
  660.  *  AFCB is created and initialized to empty. If the file is to be opened,
  661.  *  the existing file is accessed, and the AFCB initialized for that file.
  662.  *  The argument opn is 'C' to create a file and 'O' to open a file.
  663.  */
  664.  
  665. void open_dir_io(int opn)                                    /*;open_dir_io*/
  666. {
  667.     int     *item_tt_ptr;
  668.     long    eof_pos;
  669.     int     type;
  670.  
  671.     POP_PTR(item_tt_ptr);              /* pop generic type */
  672.  
  673.     type = TYPE(item_tt_ptr);
  674.     if (type == TT_U_ARRAY || type == TT_U_RECORD) {
  675.         predef_raise(USE_ERROR,
  676.           "Unconstrained types not permitted for direct IO");
  677.     }
  678.     open_file();
  679.     DLENGTH = SIZE(item_tt_ptr) * sizeof(int);
  680.  
  681. #ifdef SYSTEM_V
  682.     if (strlen(IOFNAME) > 14) predef_raise(NAME_ERROR,"Invalid file name");
  683. #endif
  684.  
  685.     if (opn == 'C') {
  686.         IOFDESC = fopen_bin(IOFNAME,"w+");
  687.         if (IOFDESC == NULL) predef_raise(NAME_ERROR,"Invalid filename");
  688.         DPOS = 1;
  689.         DSIZE = 0;
  690.     }
  691.     else {
  692.         IOFDESC = fopen_bin(IOFNAME, "r");
  693.         if (IOFDESC == NULL) predef_raise(NAME_ERROR,"File not found");
  694.         if (IOMODE == DIO_IN_FILE)
  695.             ;
  696.         else if (IOMODE == DIO_OUT_FILE) {
  697.             fclose(IOFDESC);
  698.             IOFDESC = fopen_bin(IOFNAME, "w");
  699.         }
  700.         else {
  701.             fclose(IOFDESC);
  702.             IOFDESC = fopen_bin(IOFNAME, "r+");
  703.         }
  704.         check_opened_ok();
  705.  
  706.         DPOS = 1;
  707.         fseek(IOFDESC, 0L, 2);
  708.         eof_pos = ftell(IOFDESC);
  709.         DSIZE = eof_pos / DLENGTH;
  710.     }
  711.     *get_argument_ptr(0) = filenum;
  712. }
  713.  
  714.  
  715. /* OPEN_FILE */
  716.  
  717. /*  This routine is used for all file types to perform the basic operations
  718.  *  of acquiring the parameters for an open and constructing an AFCB. On
  719.  *  return the AFCB is built and filenum references the afcbs entry set.
  720.  */
  721.  
  722. static void open_file()                                             /*;open_file*/
  723. {
  724.     int     *file_ptr;
  725.  
  726.     file_ptr = get_argument_ptr(0);
  727.     check_ifile_closed(file_ptr);
  728.  
  729.     filenum = 1;
  730.     while(afcbs[filenum - 1] != 0 && filenum < 21)
  731.         filenum++;
  732.     if (afcbs[filenum - 1] != 0)
  733.         predef_raise(USE_ERROR, "Too many files open");
  734.  
  735.     afcbs[filenum - 1] = (struct afcb  *)(predef_alloc(sizeof(struct afcb)));
  736.  
  737.     IOFDESC = NULL;
  738.  
  739.     IOMODE = get_argument_value(2);
  740.  
  741.     get_string_value(4);
  742.     IOFNAME = make_string();
  743.  
  744.     get_string_value(8);
  745.     IOFORM = make_string();
  746.  
  747.     /* Check for temporary file */
  748.  
  749.     if (*IOFNAME == '\0') {
  750.         struct tfile   *tfilep;
  751. #ifdef IBM_PC
  752.         IOFNAME = predef_alloc(L_tmpnam);
  753.         tmpnam(IOFNAME);
  754. #else
  755.         IOFNAME = predef_alloc(15);
  756.         strcpy(IOFNAME, "ADATEMP_XXXXXX");
  757.         IOFNAME = mktemp(IOFNAME);
  758. #endif
  759.         tfilep = (struct tfile *)(predef_alloc(sizeof(struct tfile)));
  760.         tfilep -> tfile_next = tfiles;
  761.         tfiles = tfilep;
  762.         strcpy(tfiles -> tfile_name, IOFNAME);
  763.     }
  764.  
  765.     /* If not temporary file, make sure it is not already open */
  766.  
  767.     else
  768.         check_xfile_closed(IOFNAME);
  769. }
  770.  
  771. /* CLOSE_FILE */
  772.  
  773. /* Close file and deallocate the AFCB */
  774.  
  775. void close_file()                                                /*;close_file*/
  776. {
  777.     fclose(IOFDESC);
  778.     predef_free(IOFNAME);
  779.     predef_free(IOFORM);
  780.     predef_free((char *)(afcbs[filenum - 1]));
  781.     afcbs[filenum - 1] = 0;
  782. }
  783.  
  784. /* PREDEF_TERM : Termination routine for Input/Output packages. */
  785.  
  786. void predef_term()                                           /*;predef_term*/
  787. {
  788.     /* close all open files except stdin and stdout */
  789.  
  790.     for (filenum = 3; filenum <= MAXFILES; filenum++) {
  791.         if (afcbs[filenum - 1] != NULL && IOFDESC != NULL) {
  792.             if (IOMODE == SIO_OUT_FILE)
  793.                 close_file();
  794.             else if (IOMODE == DIO_OUT_FILE || IOMODE == DIO_INOUT_FILE)
  795.                 close_file();
  796.             else if (IOMODE == TIO_OUT_FILE)
  797.                 close_textio();
  798.         }
  799.     }
  800.  
  801.     /* Delete temporary files upon completion of the main program */
  802.  
  803.     while(tfiles != 0) {
  804. #ifdef vms
  805.         delete(strjoin((tfiles -> tfile_name),";"));
  806. #else
  807.         unlink(tfiles -> tfile_name);
  808. #endif
  809.         tfiles = tfiles -> tfile_next;
  810.     }
  811. #ifdef IBM_PC
  812.     /* Flush input buffer if there is something there, since MS_DOS
  813.      * will retain the unwanted information for next program execution.
  814.      * Check that stdin is connected to the console and that the last
  815.      * character read from stdin is not EOF (this will be the case also
  816.      * if we have not read anything from stdin) and not LINE_FEED.
  817.      */
  818.     if ( isatty(fileno(stdin))  && 
  819.       last_char_input != EOF && last_char_input != LINE_FEED) {
  820.         filenum = 1;    /* stdin */
  821.         do {
  822. #ifdef IO_EOF
  823.             last_char_input = fgetceof(IOFDESC);
  824. #else
  825.             last_char_input = fgetc(IOFDESC);
  826. #endif
  827.         } while ( last_char_input != LINE_FEED && last_char_input != EOF);
  828.     }
  829. #endif
  830. }
  831.  
  832. /* PREDEF_ALLOC */
  833.  
  834. /* Procedure to allocate storage for use by PREDEF. The argument is the
  835.  * length of storage required in bytes. For now we allocate this storage
  836.  * on the main C heap. Later on when we extend the Ada heap to multiple
  837.  * segments, we may allocate on the Ada heap.
  838.  */
  839.  
  840. char *predef_alloc(int s)                                     /*;predef_alloc*/
  841. {
  842.     return (char *) malloc(s);
  843. }
  844.  
  845. /* Procedure to free storage previously acquired by a call to PREDEF_ALLOC */
  846.  
  847. void predef_free(char *p)                                      /*;predef_free*/
  848. {
  849.     free(p);
  850. }
  851.  
  852. #ifdef IBM_PC
  853. /* if need to distinguish binary and text files */
  854.  
  855. FILE *fopen_bin(char *fname, char *fmode)                    /*;fopen_bin*/
  856. {
  857.     char mode[30];
  858.     strcpy(mode,fmode);
  859.     strcat(mode,"b");
  860. #ifdef IO_EOF
  861.     clear_eof();
  862. #endif
  863.     return fopen(fname, mode);
  864. }
  865.  
  866. FILE *fopen_txt(char *fname, char *fmode)                    /*;fopen_txt*/
  867. {
  868.     char mode[30];
  869.     strcpy(mode,fmode);
  870.     strcat(mode,"t");
  871. #ifdef IO_EOF
  872.     clear_eof();
  873. #endif
  874.     return fopen(fname, mode);
  875. }
  876. #endif
  877.  
  878. #ifdef IO_EOF
  879. static void clear_eof()                                        /*;clear_eof*/
  880. {
  881.     /* reset eof flag for those systems that need it; that is, those systems
  882.      * that do not return EOF properly when called more than once at end of
  883.      * file
  884.      */
  885.     afcbs[filenum-1]->io_eof = 0;
  886. }
  887.  
  888. static int fgetceof(FILE *file)                /*;fgetceof*/
  889. {
  890.     int c;
  891.  
  892.     if (IOEOF) c = EOF;
  893.     else {
  894.         c = fgetc(file);
  895.         if (c==EOF)
  896.             IOEOF = 1; /* set flag to avoid reading past end */
  897.     }
  898.     return c;
  899. }
  900. #endif
  901.  
  902. #ifdef DEBUG_PREDEF
  903. static int pchars=0;
  904. static int gchars=0;
  905.  
  906. static void gchar(char *msg, int c)                                    /*;gchar*/
  907. {
  908.     gchars++;
  909.     printf("\ngchar %03d %s %03d %02x ",gchars,msg,c,c);
  910.     if (c>=0 && c<32) printf("^%c",c+64);
  911.     else if (c>32 && c<127) printf(" %c",c);
  912.     else printf(" ");
  913.     printf("\n");
  914. }
  915.  
  916. static void pchar(char *msg, int c)                                    /*;pchar*/
  917. {
  918.     pchars++;
  919.     printf("\npchar %03d %s %03d %02x ",pchars,msg,c,c);
  920.     if (c>=0 && c<32) printf("^%c",c+64);
  921.     else if (c>32 && c<127) printf(" %c",c);
  922.     else printf(" ");
  923.     printf("\n");
  924. }
  925. #endif
  926.